package com.powerhua.core.base;

import com.powerhua.core.base.bean.BaseField;
import com.powerhua.core.base.bean.BaseModel;
import com.powerhua.core.base.bean.IField;
import com.powerhua.core.base.bean.IModel;
import com.powerhua.core.db.DatabaseManager;
import com.powerhua.core.utils.WebPathUtils;
import com.powerhua.core.xml.XmlUtil;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;

/**
 *
 * @author Brian.Xie 
 */
public class BaseModelCacheManager {

    private static Map<String, IModel> models;
    private static BaseModelCacheManager instance;
    private final static Log LOG = LogFactory.getLog(BaseModelCacheManager.class);

    /**
     * 
     */
    private BaseModelCacheManager() {
    }

    /**
     * 
     * @return
     */
    public static synchronized BaseModelCacheManager getInstance() {
        if (instance == null) {
            instance = new BaseModelCacheManager();
            init();
        }

        return instance;
    }

    /**
     * 
     */
    private static void init() {
        models = new HashMap<String, IModel>();
        String xmlFile = WebPathUtils.getWebClassesPath() + "/models.xml";
        Document doc = XmlUtil.getDocument(xmlFile);
        Element root = doc.getRootElement();
        List list = root.elements("model");
        if (list == null) {
            LOG.warn("No model config in model file (" + xmlFile + ")");
            return;
        }
        for (int i = 0; i < list.size(); i++) {
            Element element = (Element) list.get(i);
            String attrId = element.attributeValue("id");
            String attrTable = element.attributeValue("table");
            IModel model = generateModel(attrId, attrTable);
            generateFields(model);
            models.put(attrId, model);
        }
    }

    /**
     * 
     * @param modelId
     * @param modelTable
     * @return
     */
    private static IModel generateModel(String modelId, String modelTable) {
        IModel model = new BaseModel();
        model.setModelId(modelId);
        model.setModelTable(modelTable);
        return model;
    }

    /**
     * 
     * @param model
     */
    private static void generateFields(IModel model) {
        Map<String, IField> fields = new HashMap<String, IField>();
        List<String> fieldNames = new ArrayList<String>();
        IField pkField = null;
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSetMetaData rsmt = null;
        ResultSet pkRs = null;
        String sql = "select * from " + model.getModelTable();
        try {
            conn = DatabaseManager.getConnection();

            DatabaseMetaData dbMd = conn.getMetaData();
            pkRs = dbMd.getPrimaryKeys(null, null, model.getModelTable());
            if (pkRs.next()) {
                pkField = new BaseField();
                pkField.setName("" + pkRs.getObject(4));
            /*
            System.err.println("TABLE_CAT : " + pkRs.getObject(1));
            System.err.println("TABLE_SCHEM: " + pkRs.getObject(2));
            System.err.println("TABLE_NAME : " + pkRs.getObject(3));
            System.err.println("COLUMN_NAME: " + pkRs.getObject(4));
            System.err.println("KEY_SEQ : " + pkRs.getObject(5));
            System.err.println("PK_NAME : " + pkRs.getObject(6));
             */
            } else {
                LOG.error("No primary key definition in table (" + model.getModelTable() + ")");
                model.setFields(fields);
                return;
            }

            ps = conn.prepareStatement(sql);
            rsmt = ps.getMetaData();
            int count = rsmt.getColumnCount();
            for (int i = 1; i < count + 1; i++) {
                IField baseField = new BaseField();
                String columnName = rsmt.getColumnName(i);
                String columnType = rsmt.getColumnTypeName(i).toLowerCase();
                String columnClazz = rsmt.getColumnClassName(i);
                int columnLength = rsmt.getColumnDisplaySize(i);

                if (columnName.equals(pkField.getName())) {
                    pkField.setType(columnType);
                    pkField.setClazz(columnClazz);
                    pkField.setLength(columnLength);
                } else {
                    baseField.setName(columnName);
                    baseField.setType(columnType);
                    baseField.setClazz(columnClazz);
                    baseField.setLength(columnLength);
                    fields.put(columnName, baseField);
                    fieldNames.add(columnName);
                }
            }
        } catch (SQLException e) {
            LOG.error("Generate model field exception, model id (" + model.getModelId() + "), model table (" + model.getModelTable() + ") ", e);
            return;
        } finally {
            DatabaseManager.closePreparedStatement(ps);
            DatabaseManager.closeConnection(conn);
        }

        model.setPk(pkField);
        model.setFields(fields);
        model.setFieldNames(fieldNames);
    }

    /**
     * 
     * @param modelId
     * @return
     */
    public IModel getModel(String modelId) {
        IModel model = models.get(modelId);
        return model;
    }
}
